﻿using AiMoRhino.Main;
using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using System;
using System.Collections.Generic;
using System.Threading;

namespace AiMoRhino.ScriptInstance.LinkSelect
{
    class Linker : IDisposable
    {
        public List<LinkedItemBase> Items { get; } = new List<LinkedItemBase>();
        HashSet<Guid> RegisterdIds { get; } = new HashSet<Guid>();
        LinkedSelectForm ManagerForm { get; set; }
        public Linker()
        {
            RhinoDoc.AddRhinoObject -= RhinoDoc_ObjectChanged;
            RhinoDoc.DeleteRhinoObject -= RhinoDoc_ObjectChanged;

            RhinoDoc.AddRhinoObject += RhinoDoc_ObjectChanged;
            RhinoDoc.DeleteRhinoObject += RhinoDoc_ObjectChanged;

            Command.EndCommand -= Command_EndCommand;
            Command.EndCommand += Command_EndCommand;
        }

        void Command_EndCommand(object sender, CommandEventArgs e)
        {
            if (m_NeedRunUpdate && e.CommandEnglishName != CSharpScriptCommand.Instance.EnglishName)
            {
                new Thread(ExcuteCommand).Start();
                m_NeedRunUpdate = false;
            }
        }

        void RhinoDoc_ObjectChanged(object sender, RhinoObjectEventArgs e)
        {
            if (m_UpdateOn && m_NoCommandExcuting)
            {
                if (RegisterdIds.Contains(e.ObjectId))
                {
                    m_NeedRunUpdate = true;
                }
            }
        }
        void ExcuteCommand()
        {
            m_NoCommandExcuting = false;
            if (!Command.InCommand())
            {
                RhinoApp.InvokeAndWait(new Action(() => { RhinoApp.ExecuteCommand(RhinoDoc.ActiveDoc, CSharpScriptCommand.Instance.EnglishName); }));
                ManagerForm.UpdateListItem();//
            }
            m_NoCommandExcuting = true;
        }

        bool m_NeedRunUpdate = false;

        bool m_NoCommandExcuting = true;

        bool m_UpdateOn = false;
        public void StartUpdate()
        {
            m_UpdateOn = true;
        }

        public void StopUpdate()
        {
            m_UpdateOn = false;
        }

        bool RegisterItem(LinkType linkType, bool isMultiple, out LinkedItemBase obj)
        {
            bool re = false;
            if (Items.Count > getOrder)
            {
                re = GetItem(linkType, out obj);
            }
            else
            {
                if (isMultiple)
                    Items.Add(new LinkedMultipleItem(linkType));
                else
                    Items.Add(new LinkedOneItem(linkType));
                ShowWindow();
                StartUpdate();
                obj = null;
            }
            getOrder++;
            if (getOrder > 100) throw new Exception("无法处理超过100个Link请求。");
            return re;
        }

        public void UpdateRegisteredIds()
        {
            RegisterdIds.Clear();
            foreach (LinkedItemBase itemBase in Items)
            {
                RegisterdIds.UnionWith(itemBase.AllIDs);
            }
        }

        public bool RegisterItem(LinkType linkType, out LinkedMultipleItem multipleLink)
        {
            bool re = RegisterItem(linkType, true, out LinkedItemBase itemBase);
            multipleLink = itemBase as LinkedMultipleItem;
            return re;
        }
        public bool RegisterItem(LinkType linkType, out LinkedOneItem oneLink)
        {
            bool re = RegisterItem(linkType, false, out LinkedItemBase itemBase);
            oneLink = itemBase as LinkedOneItem;
            return re;
        }

        void ShowWindow()
        {
            if (ManagerForm == null || ManagerForm.IsDisposed || ManagerForm.Disposing)
            {
                ManagerForm = new LinkedSelectForm(this);
                ManagerForm.Show();
                ManagerForm.BringToFront();
            }
            ManagerForm.UpdateListItem();
        }
        int getOrder = 0;
        //每次RunCommmand之前都需要清空Get
        public void ResetGetOrder()
        {
            getOrder = 0;
        }
        bool GetItem(LinkType linkType, out LinkedItemBase obj)
        {
            obj = null;
            if (Items.Count > getOrder)
            {
                LinkedItemBase linkedItem = Items[getOrder];
                if (linkedItem.CurrentLinkType == linkType && linkedItem.HasLinkedObject && linkedItem.GetLinkedGeometry())
                {
                    obj = linkedItem;
                    return true;
                }
            }
            return false;
        }

        public void Dispose()
        {
            RhinoDoc.AddRhinoObject -= RhinoDoc_ObjectChanged;
            RhinoDoc.DeleteRhinoObject -= RhinoDoc_ObjectChanged;
            Command.EndCommand -= Command_EndCommand;
            ManagerForm?.Close();
        }
    }
}
